package ilender.controller;

import lombok.*;

import com.google.gson.*;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.*;

import ilender.annotations.*;
import ilender.dispatching.ControllerTools;
import ilender.mappers.*;
import ilender.models.*;
import ilender.util.*;
import ilender.formatting.*;
import ilender.facebook.*;

/**
 * @see Controller
 */
@Controller("requests")
public class RequestsController{
	/**
	 * Register a request.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         category_id:(the id of the category),
	 *         title:(the title of the new request),
	 *         until_date:(the due date for the request),
	 *         description:(the description of the new request),
	 *         tags:(a comma\space separated list of tags for the new request)
	 *     }
	 * }
	 * </pre>
	 */
	public static JsonElement add(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");

		MRequest newRequest=new MRequest();
		newRequest.setCategory_id(Long.valueOf(formData.get("category_id").getAsString()));
		newRequest.setTitle(formData.get("title").getAsString());
		newRequest.setUntil_date(DateTimeFormatting.forJsonDateMidnight().parseDateTime(formData.get("until_date").getAsString()).toDateMidnight());
		newRequest.setDescription(formData.get("description").getAsString());
		newRequest.setFacebook_user_id(tools.fbUser.id);
		newRequest.setTags(
				Lists.newArrayList(StringUtils.split(formData.get("tags").getAsString()," ,"))
				);
		val requestsMapper=tools.session.getMapper(RequestsMapper.class);
		newRequest.save(requestsMapper);

		//Autorequest the items the user has marked
		if(formData.has("request_items")){
			JsonArray requestItems=formData.getAsJsonArray("request_items");
			String result="";
			ItemsMapper itemsMapper=tools.session.getMapper(ItemsMapper.class);
			for(val entry:requestItems){
				MItem item=itemsMapper.find(entry.getAsNumber().longValue());
				OffersController.registerOffer(newRequest,item,tools);
			}
		}

		//Post on wall
		if(formData.has("post_on_wall")){
			tools.fbUser.postTo(FBPostType.FEED)
				.setMessage(String.format("I need %s. Have it? Lend it to me in Rebay!",newRequest.getTitle()))
				.setLink(newRequest)
				.post();
		}

		//TODO: make it return nothing.
		return JsonTools.makeObject(
				"update",JsonTools.makeArray(
					JsonTools.makeObject("target","#lending-panel [contains=cardlets]",
						"ejs","layout/cardlet_list",
						"items",fetchCardlets(tools,""))));
	}

	/**
	 * Register a request for an existing item.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         target_item_id:(the id of the item to request),
	 *         until_date:(the due date for the request),
	 *     }
	 * }
	 * </pre>
	 */
	public static JsonElement addForExistingItem(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		RequestsMapper requestsMapper=tools.session.getMapper(RequestsMapper.class);
		ItemsMapper itemsMapper=tools.session.getMapper(ItemsMapper.class);

		MItem item=itemsMapper.find(Long.valueOf(formData.get("target_item_id").getAsString()));
		MRequest newRequest=new MRequest();

		//Copy the data from the item:
		newRequest.setFacebook_user_id(tools.fbUser.id);
		newRequest.setCategory(item.getCategory());
		newRequest.setTitle(item.getName());
		newRequest.setDescription(item.getDescription());
		newRequest.setTags(item.getTags());

		//Add the until_date the user has chosen:
		newRequest.setUntil_date(DateTimeFormatting.forJsonDateMidnight().parseDateTime(formData.get("until_date").getAsString()).toDateMidnight());

		newRequest.save(requestsMapper);
		return OffersController.registerOffer(newRequest,item,tools);
	}

	/**
	 * Search for requests.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         search_string:(the search string)
	 *     }
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (request cardlet),
	 *         ...
	 *     ]
	 * }
	 * </pre>
	 */
	public static JsonElement search(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		String searchString=formData.get("search_string").getAsString();
		val requestsMapper=tools.session.getMapper(RequestsMapper.class);
		return JsonTools.makeObject(
				"entries",fetchCardlets(tools,searchString));
	}

	/**
	 * Get requests suggestions to display for a new item.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         name:(name to search with),
	 *         tags:(tags to search with)
	 *     },
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (request cardlet),
	 *         ...
	 *     ]
	 * }
	 */
	public static JsonElement suggestForNewItem(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		String searchString=String.format("%s %s",
				formData.get("name").getAsString(),
				formData.get("tags").getAsString().replace(","," "));
		return JsonTools.makeObject(
				"entries",fetchCardlets(tools,searchString,4)
				);
	}

	/**
	 * Return a list of cardlets.
	 *
	 * @param tools The ControllerTools used for the request.
	 * @param searchString The search string.
	 * @return A JSON array containing cardlets.
	 */
	public static JsonArray fetchCardlets(ControllerTools tools,String searchString,long limit){
		val requestsMapper=tools.session.getMapper(RequestsMapper.class);
		val offersMapper=tools.session.getMapper(OffersMapper.class);
		val suggestionsMapper=tools.session.getMapper(SuggestionsMapper.class);
		val result=JsonTools.addToEach(
				tools.gson.toJsonTree(requestsMapper.searchRequests(searchString,limit)).getAsJsonArray(),
				"ejs","requests/request_cardlet");
		val idsOfRequestsAlreadyOfferedTo=offersMapper.idsOfRequestsOfferedToBy(tools.fbUser.id);
		val idsOfRequestsAlreadySuggested=suggestionsMapper.idsOfRequestsSuggestedToUser(tools.fbUser.id);
		val resultFiltered=new JsonArray();
		for(val entry:result){
			val entryObject=entry.getAsJsonObject();
			if(tools.fbUser.id==entryObject.getAsJsonObject("facebook_user").get("id").getAsLong())
				continue;
			//entryObject.addProperty("requested_by_this_user",
					//idsOfRequestsAlreadyOfferedTo.contains(Long.valueOf(entryObject.get("id").getAsString())));
			long requestId=Long.valueOf(entryObject.get("id").getAsString());
			if(idsOfRequestsAlreadyOfferedTo.contains(requestId))
				continue;
			if(idsOfRequestsAlreadySuggested.contains(requestId))
				continue;
			resultFiltered.add(entry);
		}
		return resultFiltered;
	}
	public static JsonArray fetchCardlets(ControllerTools tools,String searchString){
		return fetchCardlets(tools,searchString,0);
	}
}
